#!/usr/bin/perl

=script: rmdom.pl
|
|Version: 0.14
|
|Description: Domain removal script.
|
|Author: Gary Locke
|
|Usage:
|   ./rmdom.pl <domain>
|   ./rmdom.pl --auto <domain>   # Auto-detect server configurations. Does not remove IPs. (Use with caution!).
|
|Changelog:
| Ver. 0.1
|   5/21/2013 - Initial write.
| Ver. 0.2
|   5/23/2013 - Added nginx support.
| Ver. 0.3
|   5/24/2013 - Bug fixes.
| Ver. 0.4
|   5/28/2013 - Bug fixes;
|               updated backup handling.
| Ver. 0.5
|   5/29/2013 - Bug fixes;
|               added simple check for lighttpd;
|               added 'skip' option in getConfigManual sub;
|               added creation of basic restore script.
| Ver. 0.6
|   6/3/2013  - Bug fixes;
|               added check for IP and removal option;
|               option --auto now more automated;
|               added nginx config test.
| Ver. 0.7
|   6/4/2013 - Bug fixes;
|               added search for Apache listen directives.
| Ver. 0.8
|   6/5/2013 - Bug fixes;
|               added code to ifdown interfaces and backup ifcfg files.
| Ver. 0.9
|   6/7/2013 - Bug fixes;
|               added log file output for each removed domain (separate from restore file);
|               added check and removal of nginx IPs.
| Ver. 0.10
|   6/8/2013 - Bug fixes;
|               fixed and tested nginx IP detection;
|               added color to output.
| Ver. 0.11
|   6/10/2013 - Bug fixes;
|               less chatty output.
| Ver. 0.12
|   6/11/2013 - Bug fixes;
|               IP removal testing/tuning done.
| Ver. 0.13
|   6/12/2013 - Bug fixes;
|               Nginx now tests correctly after changes.
| Ver. 0.14
|   6/13/2013 - Bug fixes;
|               Real world testing.
|
|To do:
| Add better lighttpd support.
| Check that vhost.conf (nginx) is included in nginx.conf before automatically using it.
| Make resulting config files neater (remove consecutive empty lines (cat -s?)).
| Set default to Y for using autodetected config files (still N for remove).
| Remove domain from AWStats.
| DNS stuff (maybe just a reminder).
| Add support for standard BIND configuration.
=cut



###########################
###### Start Options ######
###########################

$use_auto               = 0; # Does not remove IPs.

$apache_config_path     = ""; # Absolute path to Apache client configuration.
$nginx_config_path      = ""; # Absolute path to nginx client configuration.

$skip_apache            = 0;
$skip_nginx             = 0;
$skip_hosts             = 0;
$skip_local_host_names  = 0;
$skip_ip_checks         = 0;

$backup_dir = "/root/newdom/rmdom";

###########################
####### End Options #######
###########################



## Start script.

## Load modules.
use File::Copy;
#use warnings;

## Must be run as root.
if ($> ne 0) {
    die("You are not root.\n");
}

## Argument validation.
$use_auto_option = 0; # Avoid warnings.
if (@ARGV > 1) {
    if ($ARGV[0] =~ /^-/) {
        if ($ARGV[0] =~ /^--auto/) {
            $use_auto = $use_auto_option = 1;
        } else {
            &displayHelp;
        }
    } else {
        &displayHelp;
    }
} elsif (@ARGV eq 1) {
    if ($ARGV[0] =~ /^-/) {
        &displayHelp;
    }
}

## Set variables.
($day, $month, $year)   = (localtime)[3,4,5];
$month                  = sprintf '%02d', $month+1;
$day                    = sprintf '%02d', $day;
$year                   = $year+1900;
$date                   = $year.$month.$day;
$utime                  = time;
$htime                  = localtime;
$htime                  =~ s.\ \ .\ .;
$clear                  = `clear`;
$nginx_bin              = "/usr/local/nginx/sbin/nginx";
$nginx_server_conf      = &getNginxServerConf;
$a_enabled              = `chkconfig --list|egrep ^httpd`;
$n_enabled              = `chkconfig --list|egrep ^nginx`;
$l_enabled              = `chkconfig --list|egrep ^lighttpd`;
$made_apache_changes    = 0;
$made_nginx_changes     = 0;
$manual_skip_config     = 0;

## Set colors.
$Red = "\e[31m";
$Green = "\e[32m";
$Yellow = "\e[33m";
$Blue = "\e[34m";
$Purple = "\e[35m";
$Cyan = "\e[36m";
$Reset = "\e[0m";

## Create $backup_dir if it doesn't already exist.
unless (-d $backup_dir) {
    unless(mkdir($backup_dir)) {
        die $Red."Could not create ".$backup_dir."\n".$Reset;
    }
}

## Create $backup_logs if it doesn't already exist.    
$backup_logs = $backup_dir."/logs";
unless (-d $backup_logs) {
    unless(mkdir($backup_logs)) {
            die $Red."Could not create ".$backup_logs."\n".$Reset;
    }
}

## Remove trailing slash from $backup_dir.
$backup_dir =~ s./$..;

## Ask user for domain if not given as command line argument and not using auto-detect for config paths.
if ($use_auto_option eq 1 && defined($ARGV[1])) {
    $dom = lc $ARGV[1];
    $updom = uc $dom;
    print "Starting removal for domain '".$dom."'\n";
} elsif (defined($ARGV[0])) {
    $dom = lc $ARGV[0];
    $updom = uc $dom;
    print "Starting removal for domain '".$dom."'\n";
} else {
    for(;;) {
        print "Enter a domain name: ";
        $dom = lc <STDIN>;
        if ($dom =~ /^.+\..+$/) {
            chomp($dom);
            $updom = uc $dom;
            last;
        } else {
            print $Red."Invalid entry.\n".$Reset;
        }
    }
}


## Apache logic.
for(;;) {
    if ($skip_apache eq 0 && $manual_skip_config eq 0) {
        print $Cyan."\nApache:\n".$Reset;
        if ($a_enabled !~ /[Oo][Nn]/) {
            unless ($use_auto eq 1) {
                print $Yellow."\nNOTICE: Apache doesn't appear to be enabled on this server.\n";
                print "        Set \"\$skip_apache = 0;\" in this script to ignore all Apache configs.\n\n".$Reset;
            }
        }
        if ($use_auto eq 1) {
            &autoDetectApacheConf;
            $a_conf = $a_auto_conf;
            unless (-e $a_conf) {
                print "Could not auto-detect Apache config. Skipping Apache...\n";
                last;
            }
        } else {
            if ($apache_config_path ne "") {
                $a_conf = $apache_config_path;
                print "Using path \"".$a_conf."\" as specified in this script's configuration.\n";
            } else {
                &autoDetectApacheConf;
                if ($a_auto_conf =~ /$client_id/ && -e $a_auto_conf) {
                    print "Use ".$a_auto_conf."? [y/N]: ";
                    $use_a_auto_conf = <STDIN>;
                    chomp($use_a_auto_conf);
                    if ($use_a_auto_conf =~ /[Yy]/) {
                        $a_conf = $a_auto_conf;
                    } else {
                        $a_conf = &getConfigManual("Apache client configuration file");
                    }
                } else {
                    $a_conf = &getConfigManual("Apache client configuration file");
                }
            }
        }
        unless ($manual_skip_config eq 1) {
            &doApache($a_conf);
            $a_conf_lan = $a_conf.".lan";
            if (-e $a_conf_lan) {
                $is_lan = 1;
                &doApache($a_conf_lan);
            } else {
                $is_lan = 0;
            }
            last;
        }
    } else {
        $manual_skip_config = 0;
        print "Skipping Apache...\n";
        last;
    }
}

## nginx logic.
for(;;) {
    if ($skip_nginx eq 0 && $manual_skip_config eq 0) {
        print $Cyan."\nnginx:\n".$Reset;
        if ($n_enabled !~ /[Oo][Nn]/) {
            unless ($use_auto eq 1) {
                print $Yellow."\nNOTICE: nginx doesn't appear to be enabled on this server.\n";
                print "        Set \"\$skip_nginx = 0;\" in this script to ignore all nginx configs.\n\n".$Reset;
            }
        }
        $nginx_default_conf = "/usr/local/nginx/conf/vhost.conf";
        if ($use_auto eq 1) {
            if (-e $nginx_default_conf) {
                print "Using default nginx config file: ".$nginx_default_conf."\n"; 
                $n_conf = $nginx_default_conf;
            } else {
                print "Default nginx config (".$nginx_default_conf.") not found. Skipping nginx...\n";
                last;
            }
        } else {
            if ($nginx_config_path ne "") {
                if (-e $nginx_config_path) {
                    $n_conf = $nginx_config_path;
                    print "Using path \"".$n_conf."\" as specified in this script's configuration.\n";
                } else {
                    print $Red."Cannot find path \"".$n_conf."\" as specified in this script's configuration.\n".$Reset;
                    undef($nginx_config_path);
                }
            } elsif (-e $nginx_default_conf) {
                &confirm("Use ".$nginx_default_conf."? [y/N]: ");
                if ($confirm =~ /[Yy]/) {
                    $n_conf = $nginx_default_conf;
                } else {
                    $n_conf = &getConfigManual("nginx vhost file");
                }
            } else {
                $n_conf = &getConfigManual("nginx vhost file");
            }
        }
        unless ($manual_skip_config eq 1) {
            &doNginx($n_conf);
            last;
        }
    } else {
        print "Skipping nginx...\n";
        last;
    }
}

## If any configurations files were updated, update other files accordingly.
if ($made_apache_changes eq 1 || $made_nginx_changes eq 1) {
    if ($skip_hosts eq 0) {
        open(OH, "<", "/etc/hosts");
        open(NH, ">", "/etc/hosts.new") or print $Red."ERROR: Can't open /etc/hosts.new for writing.\n".$Reset;
        while(<OH>) {
            if ($_ !~ /[[:blank:]]$dom[[:blank:]]*$/) {
                print NH $_;
            }
        }
        close(OH);
        close(NH);
        print "Updating hosts file...";
        $hosts_backup = "/etc/hosts.".$date;
        unless (-e $hosts_backup) {
            copy("/etc/hosts",$hosts_backup) or print $Red."\nERROR: Cannot back up hosts file.\n".$Reset;
        }
        move("/etc/hosts.new","/etc/hosts") or print $Red."\nERROR: Cannot update hosts file.\n".$Reset;
        print "done.\n";
    } else {
        print "Skipping hosts file...\n";
    }
    
    if ($skip_local_host_names eq 0) {
        if (-e "/etc/mail/local-host-names") {
            open(OL, "<", "/etc/mail/local-host-names");
            open(NL, ">", "/etc/mail/local-host-names.new") or print $Red."ERROR: Can't open /etc/mail/local-host-names.new for writing.\n".$Reset;
            while(<OL>) {
                if ($_ !~ /^[[:blank:]]*$dom[[:blank:]]*$/) {
                    print NL $_;
                }
            }
            close(OL);
            close(NL);
            print "Updating local-host-names file...";
            $local_host_names_backup = "/etc/mail/local-host-names.".$date;
            unless (-e $local_host_names_backup) {
                copy("/etc/mail/local-host-names",$local_host_names_backup) or print $Red."\nERROR: Cannot back up /etc/mail/local-host-names.\n".$Reset;
            }
            move("/etc/mail/local-host-names.new","/etc/mail/local-host-names") or print $Red."\nERROR: Cannot update /etc/mail/local-host-names.\n".$Reset;
            print "done.\n";
        }
    } else {
        print "Skipping sendmail's local-host-names file...\n\n";
    }
    if ($docroot) {
        $docroot_file = $backup_dir."/docroots.txt";
        open(DR,">>",$docroot_file);
        print DR $docroot."\n";
        close(DR);
    }
    &outputResults
} else {
    print "\nNo changes made.\n";
    exit;
}

##########################################
### ONLY SUBROUTINES BEYOND THIS POINT ###
##########################################

sub displayHelp {
    die("\nUsage:\n  ".$0." <domain>\n  ".$0." --auto <domain>\t# Auto-detect configuration files. Does not remove IPs. (Use with caution!).\n\nRemoved configs are stored in ".$backup_dir." (configurable).\n\n");
}

## Get confirmation from stdin. Takes a second parameter "noauto" to avoid automatically confirming when using the --auto option.
sub confirm {
    undef($confirm);
    print $_[0];
    if ($use_auto eq 1 && $_[1] !~ /noauto/) {
        print "(confirmed automatically)\n";
        $confirm = "y";
    } else {
        $confirm = <STDIN>;
        chomp($confirm);
        print "\n";
    }
    print "\n";
}

## Get client ID by parsing the MOTD.
sub getClientID {
    open(MOTD, "/etc/motd");
    while ($motd = <MOTD>) {
        if ($motd =~ /^[[:blank:]]*[Cc]lient:[[:blank:]]*/) {
            @motd_client_id = split(/ +/,$motd);
            return $motd_client_id[1];
            last;
        }
    }
    close(MOTD);
}

## Get configuration files if not specified in the script's options or autodetected.
sub getConfigManual {
    $manual_skip_config = 0;
    for(;;) {
        print "Enter absolute path to $_[0] ['s' to skip]: ";
        $path = <STDIN>;
        chomp($path);
        if ($path =~ /^[Ss](KIP|kip)?$/) {
            $manual_skip_config = 1;
            last;
        } else {
            if ($path !~ /^$/) {
                if (-e $path) {
                     return $path;
                     last;
                } else {
                     print "\n$path doesn't appear to exist. Try again.\n\n";
                }
            }
        }
    }
}

## Remove an IP from the server.
sub removeIP {
    if (-e "/etc/sysconfig/network-scripts/ifcfg-".$_[1]) {
        print "Bringing down ".$_[1]."...\n";
        open(IFDOWN,"ifdown /etc/sysconfig/network-scripts/ifcfg-".$_[1]." 2>&1 |");
        while ($ifdown_error = <IFDOWN>) {
            print $ifdown_error."\n";
        }
        close(IFDOWN);
        print "Backing up network script file...\n";
        $bk_net_scripts = $backup_dir."/network-scripts";
        unless (-d $bk_net_scripts) {
            if (mkdir($bk_net_scripts)) {
                open(BKIF,"mv /etc/sysconfig/network-scripts/ifcfg-".$_[1]." ".$bk_net_scripts." 2>&1 |"); 
            } else {
                open(BKIF,"mv /etc/sysconfig/network-scripts/ifcfg-".$_[1]." ".$backup_dir." 2>&1 |");
            }
        } else {
            open(BKIF,"mv /etc/sysconfig/network-scripts/ifcfg-".$_[1]." ".$bk_net_scripts." 2>&1 |");
        }
        while ($ifbk_error = <BKIF>) {
            print $ifbk_error."\n";
        }
        close(BKIF);
    } else {
        print "Could not find interface file (looked for /etc/sysconfig/network-scripts/ifcfg-".$_[1]."). Skipping IP removal.\n";
    }
}

## Final output block.
sub outputResults {
    open(RLOG,">>",$backup_logs."/".$dom.".log");
    print RLOG $htime."\n";
    print RLOG "Domain: ".$updom."\n";
    #print $clear;
    print "\n".$Cyan."Domain removed!\n".$Reset;
    print "\n\tDomain: ".$updom."\n";
    if ($docroot) {
        print RLOG "Apache DocumentRoot: ".$docroot."\n";
        print "\tApache document root: ".$docroot."\n";
    }

=unused for now
    if ($apache_ip) {
        print RLOG "apache IP: ".$apache_ip."\n";
    }
    if ($nginx_ip) {
        print RLOG "nginx IP: ".$nginx_ip."\n";
    }
    if ($lighttpd_ip) {
        print RLOG "lighttpd IP: ".$lighttpd_ip."\n";
    }
=cut

    print RLOG "Removed from apache?: ";
    print "\n\tAPACHE: ";  
    if ($made_apache_changes eq 1) {
        print RLOG "Y\n";
        if (&configTestApache eq 1) {
            print $Green."Config check passed.".$Reset."\n";
        } else {
            if ($a_enabled =~ /[Oo][Nn]/) {
                print $Red."Config check failed!\n".$Reset;
            } else {
                print $Red."Config check failed! Is Apache used on this server?\n".$Reset;
            }
        }
    } else {
        print RLOG "N\n";
        print "No changes made.\n";
    }
    print RLOG "Removed from nginx?: ";
    print "\tNGINX: ";
    if ($made_nginx_changes eq 1) {
        print RLOG "Y\n";
        if (&configTestNginx eq 1) {
            print $Green."nginx config check passed.".$Reset."\n";
        } else {
            if ($n_enabled =~ /[Oo][Nn]/) {
                print $Red."nginx config check failed.\n".$Reset;
            } else {
                print $Red."nginx config check failed. Is nginx used on this server?\n".$Reset;
            }
        }
    } else {
        print RLOG "N\n";
        print "No changes made.\n";
    }
    print RLOG "Removed from lighttpd?: ";
    print "\tLIGHTTPD: ";
    if ($l_enabled =~ /[Oo][Nn]/) {
        print RLOG "N\n";
        print $Yellow."Not supported. Check configuration manually.\n".$Reset;
    } else {
        print RLOG "n/a\n";
        print "Not used on this server.\n";
    }
    if ($skip_hosts eq 0) {
        print RLOG "/etc/hosts updated.\n";
    }
    if ($skip_local_host_names eq 0) {
        print RLOG "/etc/mail/local-host-names updated.\n";
    }
    print RLOG "Note: Removed host configurations stored in ".$backup_dir.".\n\n";
    if ($a_conf_backup || $a_conf_backup_lan || $n_conf_backup || $hosts_backup || $local_host_names_backup) {
        $restore_script = $backup_dir."/rmdom_restore.sh";
        open(RS, ">", $restore_script) or print $Red."ERROR: Could not create restore script. Manually restore using backup files ending in $date.\n".$Reset;
        if(tell(RS) != -1) {
            print "\n\tRestore script:".$Cyan." sh $restore_script\n\n".$Reset;
            if ($a_conf_backup) {
                print RS "mv -f ".$a_conf_backup." ".$a_conf."\n";
            }
            if ($a_conf_backup_lan) {
                print RS "mv -f ".$a_conf_backup_lan." ".$a_conf_lan."\n";
            }
            if ($n_conf_backup) {
                print RS "mv -f ".$n_conf_backup." ".$n_conf."\n";
            }
            if ($hosts_backup) {
                print RS "mv -f ".$hosts_backup." /etc/hosts\n";
            }
            if ($local_host_names_backup) {
                print RS "mv -f ".$local_host_names_backup." /etc/mail/local-host-names\n";
            }
            close(RS);
        }
    }
    close(RLOG);
    print $Cyan."Don't forget to remove the domain(s) from DNS and any removed IPs from cs1024!\n\n".$Reset;
}

##############
### APACHE ###
##############

## Starting point for Apache operations.
sub doApache {
    open(HT, "<", $_[0]);
    undef(@a_conf);
    while(<HT>) {
        chomp;
        push(@a_conf, $_);
    }
    &sortApache($dom);
    if (@a_remove) {
        #print $clear;
        foreach (@a_remove) {
            print $_."\n";
        }
        &confirm("\nRemove the host(s) above from $_[0]? [y/N]: ");
        if ($confirm =~ /[Yy]/) {
            $made_apache_changes = 1;
            unless ($use_auto eq 1) {
                unless ($skip_ip_checks eq 1) {
                    unless ($is_lan eq 1) {
                        &checkApacheIP;
                    }
                } else {
                    print "Skip IP checks option enabled. Skipping IP check.\n";
                }
            } else {
                print "Automatic mode is set. Skipping IP check.\n";
            }
            &backupApache($dom, $_[0]);
            &updateApache($dom, $_[0]);
            if ($remove_apache_listen eq 1) {
                &removeApacheListen;
            }
            &getDocRootApache(@a_remove);
        } else {
            print "Skipping...\n\n";
        }
    } else {
        print "\nNothing found in $_[0].";
        unless ($use_auto eq 1) {
            print " Enter to continue...\n";
            $continue = <STDIN>;
        } else {
            print "\n";
        }
    }
}

## Find virtual host for $dom and separate it from the rest of the Apache config.
sub sortApache {
    undef(@a_newfile);
    undef(@a_remove);
    $is_ssl = 0;
    $is_dom = 0;
    $is_vhost = 0;
    foreach (@a_conf) {
       if ($_ =~ /^<\/IfDefine/ && $is_ssl eq 1) {
            push(@a_tmp, $_);
            if ($is_dom eq 1) {
                push(@a_remove, "");
                foreach (@a_tmp) {
                    push(@a_remove, $_);
                }
            } else {
                foreach (@a_tmp) {
                    push(@a_newfile, $_);
                }
            }
            push(@a_newfile, "");
            undef(@a_tmp);
            $is_ssl = 0;
            $is_dom = 0;
        } elsif ($is_ssl eq 1) {
            push(@a_tmp, $_);
            if ($_ =~ /^[Ss]erver[Nn|Aa].*\ $_[0]/) {
                $is_dom = 1;
            }
        } elsif ($_ =~ /^<IfDefine.*SSL/) {
            push(@a_tmp, $_);
            $is_ssl = 1;
        } elsif ($_ =~ /^<\/VirtualHost/ && $is_vhost eq 1) {
            push(@a_tmp, $_);
            if ($is_dom eq 1) {
                push(@a_remove, "");
                foreach (@a_tmp) {
                    push(@a_remove, $_);
                }
            } else {
                foreach (@a_tmp) {
                    push(@a_newfile, $_);
                }
            }
            push(@a_newfile, "");
            undef(@a_tmp);
            $is_vhost = 0;
            $is_dom = 0;
        } elsif ($is_vhost eq 1) {
            push(@a_tmp, $_);
            if ($_ =~ /^[Ss]erver[Nn|Aa].*\ $_[0]/) {
                $is_dom = 1;
            }
        } elsif ($_ =~ /^<VirtualHost/) {
            push(@a_tmp, $_);
            $is_vhost = 1;
        } else {
            push(@a_newfile, $_);
        }
    }
    close(HTNEW);
}

## Check Apache IP of removed domain to see if it can be removed from the server.
sub checkApacheIP {
    if ($made_apache_changes eq 1) {
        open(HS, "/usr/sbin/httpd -S 2>&1 |");
        while (<HS>) {
            if ($_ =~ /[[:blank:]]+(www.)?$dom/) {
                chomp($_);
                unless ($_ =~ /default\ server/) {
                    @fields = split(":", $_);
                    if ($fields[0] =~ /^[0-9]/) {
                        $apache_ip = $fields[0];
                        open(IF, "ifconfig|grep -B1 $apache_ip|head -n1|");
                        while (<IF>) {
                            @iface = split(/ +/, $_);
                        }
                        if ($iface[0] =~ /^[[:blank:]]*$/) {
                            print "No interface found for Apache IP ".$apache_ip."\n\n";
                            last;
                        } elsif ($iface[0] =~ /eth/ && $iface[0] !~ /:/) {
                            print $apache_ip." appears to be on a non-virtual interface (".$iface[0].")! Skipping IP removal.\n\n";
                            last;
                        } elsif ($iface[0] =~ /eth/) {
                            print "Checking to see if its IP (".$apache_ip." on ".$iface[0].") can be removed from this server...\n";
                            foreach (@a_newfile) {
                                if ($_ =~ /$apache_ip/ && $_ !~ /[Ll]isten/) {
                                    $apache_ip_in_use = 1;
                                    last;
                                }
                            }
                            open(NET, "netstat -nlp|");
                            while (<NET>) {
                                if ($_ =~ /LISTEN/ && $_ =~ /$apache_ip/ && $_ !~ /\/httpd/ && $_ !~ /\/ntpd/) {
                                    $apache_ip_in_use =1;
                                    last;
                                } elsif ($_ =~ /LISTEN/ && $_ =~ /:::80/ && $_ =~ /\/httpd/) {
                                    $skip_apache_listens = 1;
                                    last;
                                }
                            }
                            close(NET);
                            if ($apache_ip_in_use eq 1) {
                                print "Looks like ".$apache_ip." may be in use by another host or service. No IP changes made.\n\n";
                                last;
                            } else {
                                &confirm("No other domains or services appear to use ".$apache_ip.". Want to ifdown (and backup)".$iface[0]."? [y/N]: ","noauto");
                                if ($confirm =~ /[Yy]/) {
                                    &removeIP($apache_ip,$iface[0]);
                                    unless (-e "/etc/sysconfig/network-scripts/ifcfg-".$iface[0]) {
                                        &confirm("Remove listen directive from Apache? [Y/n]: ","noauto");
                                        unless ($confirm =~ /[Nn]/) {
                                            $remove_apache_listen = 1;
                                        }
                                    } else {
                                        print "Something went wrong. Check IP configuration.\n";
                                    }
                                    last;
                                } else {
                                    print "OK. Skipping IP removal.\n";
                                    last;
                                }
                            }
                        } else {
                            print "No interface found for Apache IP ".$apache_ip.".\n\n";
                            last;
                        }
                        close(IF);
                    } else {
                        print $updom." uses name-based virtual hosting. No IP changes made.\n\n";
                        last;
                    }
                }
            }
        }
        close(HS);
    }
}

## Backup Apache virtual host configs if needed, and create restore file for removed host.
sub backupApache {
    if ($is_lan eq 1) {
        $a_conf_backup_lan = $_[1].".".$date;
        unless (-e $a_conf_backup_lan) {
            copy($_[1],$a_conf_backup_lan) or die $Red."ERROR: Backup of ".$_[1]." failed: $!".$Reset;
        }
        open(AREST, ">", $backup_dir."/".$_[0].".lan.restore") or print $Red."ERROR: Cannot open restore file ".$backup_dir."/".$_[0].".lan.restore for writing.\n".$Reset;
        foreach (@a_remove) {
            print AREST $_."\n";
        }
        close(AREST);
    } else {
        $a_conf_backup = $_[1].".".$date;
        unless (-e $a_conf_backup) {
            copy($_[1],$a_conf_backup) or die $Red."ERROR: Backup of ".$_[1]." failed: $!".$Reset;
        }
        open(AREST, ">", $backup_dir."/".$_[0].".restore") or print $Red."ERROR: Cannot open restore file ".$backup_dir."/".$_[0].".restore for writing.\n".$Reset;
        foreach (@a_remove) {
            print AREST $_."\n";
        }
        close(AREST);
    }
}

## Create updated virtual host config and move it into place.
sub updateApache {
    $htnew = $_[1].".new";
    open(HTNEW, ">", "$htnew") or die $Red."ERROR: Can't open ".$htnew." for writing.\n".$Reset;
    foreach (@a_newfile) {
        print HTNEW $_."\n";
    }
    close(HTNEW);
    print "Updating ".$_[1]."...";
    move($htnew,$_[1]) or die $Red."ERROR: Could not update ".$_[1]."Error while moving updated file into place.\n".$Reset;
    print "done.\n";
}

## Remove Listen directive from Apache.
sub removeApacheListen {
    unless ($skip_apache_listens eq 1) {
        &getApacheListenFile;
        if ($apache_listen_file) {
            $apache_listen_file_backup = $apache_listen_file.".".$date;
            unless (-e $apache_listen_file_backup) {
                print "Backing up ".$apache_listen_file." to ".$apache_listen_file_backup."\n";
                copy($apache_listen_file,$apache_listen_file_backup) or print $Red."\nERROR: Cannot backup file: ".$apache_listen_file." before removing listen directive for ".$apache_ip.". Must remove listen directive manually.\n".$Reset;
            }
            print "Removing listen directive from ".$apache_listen_file."...";
            if (-e $apache_listen_file_backup) {
                open(LF,"<",$apache_listen_file) or print $Red."ERROR: Could not open listen file for reading.\n".$Reset;
                open(NLF,">",$apache_listen_file.".new") or print $Red."ERROR: Could not open new listen file ".$apache_listen_file.".new for writing.\n".$Reset;
                while (<LF>) {
                    unless ($_ =~ /^[[:blank:]]*[Ll]isten[[:blank:]]+$apache_ip/) {
                        print NLF "$_";
                    }
                }
                move($apache_listen_file.".new",$apache_listen_file) or print $Red."ERROR: Could not updated ".$apache_listen_file." while trying to remove listen directive for ".$apache_ip."\n".$Reset;
                close(LF);
                close(NLF);
                print "done.\n";
            } else {
                print "fail. ".$Red."No backup file could be created.\n".$Reset;
            }
        }
    } else {
        print "No listen directives were found for ".$apache_ip." in Apache. Check manually.\n";
    }
}

## Find file containing Apache listen directive for $apache_ip.
sub getApacheListenFile {
    $last_listen_check = 0;
    foreach (@inc_files) {
        undef $file;
        if ($last_iteration eq 1) {
            undef($last_iteration);
            last;
        } elsif ($_ !~ /\*/) {
            chomp($file = $_);
            open(INC, $file);
            while (<INC>) {
                if ($_ =~ /^[[:blank:]]*[Ll]isten[[:blank:]]+$apache_ip/) {
                    $apache_listen_file = $file;
                    $last_iteration = 1;
                    last;
                }
            }
            close(INC);
        }
    }
}

## Find Apache *server* config.
sub getApacheServerConfig {
    open(SC, "httpd -V |");
    while (<SC>) {
        push(@HTTPDV,$_);
    }
    foreach (@HTTPDV) {
        if ($_ =~ /HTTPD_ROOT/) {
            @HTTPD_ROOT = split(/"/,$_);
            $httpd_root = $HTTPD_ROOT[1];
        } elsif ($_ =~ /SERVER_CONFIG_FILE=/) {
            @SERVER_CONFIG_FILE = split(/"/,$_);
            $server_config_file = $SERVER_CONFIG_FILE[1];
        }
    }
    if (-e $server_config_file) {
        return $server_config_file;
    } elsif (-e $httpd_root."/".$server_config_file) {
        return $httpd_root."/".$server_config_file;
    }
    close(SC);
}

## Attempt to autodetect Apache client.conf location.
sub getApacheClientConfig {
    open(CC, "<", $httpd_server_config);
    while (<CC>) {
        if ($_ =~ /^Include/) {
            @INC_LINE = split(/ +/,$_);
            push(@inc_files,$INC_LINE[1]);
        }
    }
    close(CC);
    foreach (@inc_files) {
        if ($_ =~ /$client_id/) {
            return $_;
        }
    }
}

## Use auto-detected Apache client configuration..
sub autoDetectApacheConf {
    $httpd_server_config = &getApacheServerConfig();
    chomp($client_id = &getClientID());
    chomp($a_auto_conf = &getApacheClientConfig());
}

## Get document root of removed Apache virtual host and push it into array.
sub getDocRootApache {
    foreach (@_) {
        if ($_ =~ /^[[:blank:]]*[Dd]ocument[Rr]oot/) {
            @docroot_apache = split(/ +/,$_);
            $docroot = $docroot_apache[1];
        }
    }
}

## Make sure Apache isn't horribly broken.
sub configTestApache {
    open(CTA, "httpd -t 2>&1 |");
    while (<CTA>) {
        if ($_ =~ /^Syntax\ OK$/) {
            return 1;
        }
    }
    close(CTA);
}

#############
### NGINX ###
#############

## Starting point for nginx operations.
sub doNginx {
    open(NG, "<", $_[0]);
    undef(@n_conf);
    while(<NG>) {
        chomp;
        push(@n_conf, $_);
    }
    &sortNginx();
    if (@n_remove) {
        #print $clear;
        foreach (@n_remove) {
            print $_."\n";
        }
        &confirm("\nRemove the host(s) above from $_[0]? [y/N]: ");
        if ($confirm =~ /[Yy]/) {
            $made_nginx_changes = 1;
            unless ($use_auto eq 1) {
                unless ($skip_ip_checks eq 1) {
                    &checkNginxIP;
                } else {
                    print "Skip IP checks option enabled. Skipping IP check.\n";
                }
            } else {
                print "Automatic mode is set. Skipping IP check.\n\n";
            }
            &backupNginx($dom, $_[0]);
            &updateNginx($dom, $_[0]);
        } else {
            print "Skipping...\n\n";
        }
    } elsif ($use_auto eq 1) {
        print "\nNothing found in $_[0]. Moving on...\n";
    } else {
        print "\nNothing found in $_[0]. Enter to continue...";
        $continue = <STDIN>;
    }
}

## Separate matching nginx server block from the rest.
sub sortNginx {
    $count = 0;
    foreach (@n_conf) {
        if ($is_vhost eq 1 && ($_ =~ /\{/ || $_ =~ /\}/)) {
            $numToAdd =()= $_ =~ /\{/gi;
            $numToDel =()= $_ =~ /\}/gi;
            $count = $count+$numToAdd;
            $count = $count-$numToDel;
            push(@n_tmp, $_);
        } elsif ($is_vhost eq 1 && $_ =~ /^[[:blank:]]*server_name[[:blank:]]*(www.|\.)?$dom/) {
            $is_dom = 1;
            push(@n_tmp, $_);
        } elsif ($is_vhost eq 1) {
            push(@n_tmp, $_);
        } elsif ($_ =~ /^[[:blank:]]*server[[:blank:]]*\{/) {
            $is_vhost = 1;
            $count++;
            push(@n_tmp, $_);
        } else {
            push(@n_newfile, $_);
        }
        if ($is_vhost eq 1 && $count eq 0) {
            if ($is_dom eq 1) {
                push(@n_remove, "");
                foreach (@n_tmp) {
                    push(@n_remove, $_);
                }
            } else {
                foreach (@n_tmp) {
                    push(@n_newfile, $_);
                }
            }
            undef(@n_tmp);
            $is_dom = $is_vhost = $numToAdd = $numToDel = 0;
        }
    }
}

## Backup nginx configs if needed, and create restore file for removed server block.
sub backupNginx {
    $n_conf_backup = $_[1].".".$date;
    unless (-e $n_conf_backup) {
        copy($_[1],$n_conf_backup) or die $Red."Backup of ".$_[1]." failed: $!".$Reset;
    }
    open(NREST, ">", $backup_dir."/".$_[0].".nginx.restore") or print $Red."ERROR: Cannot open restore file ".$backup_dir."/".$_[0].".nginx.restore for writing.\n".$Reset;
    foreach (@n_remove) {
        print NREST $_."\n";
    }

}

## Create new virtual host configuration for nginx and move it into place.
sub updateNginx {
    $ngnew = $_[1].".new";
    open(NGNEW, ">", "$ngnew") or die $Red."\n Can't open ".$ngnew." for writing.\n".$Reset;
    foreach (@n_newfile) {
        print NGNEW $_."\n";
    }
    close(NGNEW);
    print "Updating ".$_[1]."...";
    move($ngnew,$_[1]) or die $Red."ERROR: Could not update ".$_[1]."Error while moving updated file into place.\n".$Reset;
    print "done!\n";
}

## Check nginx IP of removed domain to see if it can be removed from the server.
sub checkNginxIP {
    if ($made_nginx_changes eq 1) {
        foreach (@n_remove) {
            if ($_ =~ /^[[:blank:]]*[Ll]isten[[:blank:]]+[0-9]/) {
                undef @fields;
                @fields = split(/ +/, $_);
                foreach (@fields) {
                    if ($_ =~ /^[0-9]/) {
                        $nginx_ip = $_;
                        $nginx_ip =~ s/;*$//;
                        last;
                    }
                }
                if ($nginx_ip) {
                    if ($nginx_ip =~ /:/) {
                        $nginx_ip =~ s/:.*//;
                    }
                    open(IF, "ifconfig|grep -B1 $nginx_ip|head -n1|");
                    undef @iface;
                    while ($line = <IF>) {
                        @iface = split(/ +/, $line);
                    }
                    if ($iface[0] =~ /^[[:blank:]]*$/) {
                        print "No interface found for nginx IP ".$nginx_ip."\n\n";
                        last;
                    } elsif ($iface[0] =~ /eth/ && $iface[0] !~ /:/) {
                        print $nginx_ip." appears to be on a non-virtual interface (".$iface[0].")! Skipping IP removal.\n\n";
                        last;
                    } elsif ($iface[0] =~ /eth/) {
                        print "In nginx, ".$updom." uses IP (".$nginx_ip." on ".$iface[0].") Checking if it can be removed from this server...\n";
                        foreach (@n_newfile) {
                            if ($_ =~ /$nginx_ip/) {
                                $nginx_ip_in_use = 1;
                                last;
                            }
                        }
                        open(NET, "netstat -nlp|");
                        while (<NET>) {
                            if ($_ =~ /LISTEN/ && $_ =~ /$nginx_ip/ && $_ !~ /\/nginx/ && $_ !~ /\/ntpd/) {
                                $nginx_ip_in_use =1;
                                last;
                            }
                        }
                        close(NET);
                        if ($nginx_ip_in_use eq 1) {
                            print "Looks like ".$nginx_ip." may be in use by another host or service. No IP changes made.\n\n";
                            last;
                        } else {
                            &confirm("No other domains or services appear to use ".$nginx_ip.". Want to ifdown (and backup)".$iface[0]."? [y/N]: ","noauto");
                            if ($confirm =~ /[Yy]/) {
                                &removeIP($nginx_ip,$iface[0]);
                                unless (-e "/etc/sysconfig/network-scripts/ifcfg-".$iface[0]) {
                                    print "IP ".$nginx_ip." successfully removed from the server...\n";
                                }
                                last;
                            } else {
                                print "OK. Skipping IP removal.\n";
                            }
                        }
                    } else {
                        print "No interface found for nginx IP ".$nginx_ip.".\n\n";
                        last;
                    }
                    close(IF);
                } else {
                    print "No IP found for ".$dom." in nginx. Skipping IP removal.\n";
                    last;
                }
            }
        }
    }
}

# Find path to nginx server configuration file.
sub getNginxServerConf {
    open(NGSERVERCONF, "$nginx_bin -t 2>&1|");
    while ($line = <NGSERVERCONF>) {
        if ($last_iteration eq 1) {
            undef($last_iteration);
            last;
        } else {
            @nginx_test = split(/ +/,$line);
            foreach $field (@nginx_test) {
                if ($field =~ /.conf$/) {
                    print $field."\n";
                    $last_iteration = 1;
                    last;
                }
            }
        }
    }
    undef($line);
    undef($field);
}

## Run nginx config test.
sub configTestNginx {
    if (-e $nginx_bin) {
        open(NGTEST, "$nginx_bin -t 2>&1|");
        while (<NGTEST>) {
            if ($_ =~ /test\ is\ successful/) {
                return 1;
                last;
            }
        }
        close(NGTEST);
    }
}

## End of script.
